//=============================================================================
///	Hash table
/**

Functions:
	table
	gethash
	sethash
	maptable

 */
//=============================================================================

#include "mhash.h"
#include "shash.h"
#include "sexp.h"
#include "ssym.h"
#include "senv.h"
#include "seval.h"

#ifndef	FALSE
#define	FALSE	(0)
#endif

//=============================================================================
// subr

static SExp f_table(int narg, SExp args[]) {
	return make_hash_table();
}

static SExp f_gethash(int narg, SExp args[]) {
	SExp key = args[0];
	SExp ht = type_check(args[1], tHash);
	SHash* p = &ht.ptr->hash;
	return gethash(key, p);
}

static SExp f_sethash(int narg, SExp args[]) {
	SExp key = args[0];
	SExp ht = type_check(args[1], tHash);
	SExp val = args[2];
	SHash* p = &ht.ptr->hash;
	sethash(key, p, val);
	return val;
}

static SExp f_maptable(int narg, SExp args[]) {
	SExp f = args[0];
	SExp ht = type_check(args[1], tHash);
	HashTable* p = &ht.ptr->hash.ht;
	HashIterator it;
	HashEntry* q;

	for (q = ht_begin(&it, p); q != NULL; q = ht_next(&it)) {
		SExp k = ptr2s(q->key);
		SExp v = ptr2s(q->val);
		SExp args;
		push_stack(nil);
		push_stack(v);
		cons_on_stack();
		push_stack(k);
		cons_on_stack();
		args = ref_stack(1);
		apply(f, args, FALSE);
		pop_stack(1);
	}

	return ht;
}


//=============================================================================

void define_hash_module(void) {
	struct {
		const char* name;
		SubrType cfunc;
		int minargnum, maxargnum;
	} f_tbl[] = {
		{	"table",		f_table,		0,	0,	},
		{	"gethash",		f_gethash,		2,	2,	},
		{	"sethash",		f_sethash,		3,	3,	},
		{	"maptable",		f_maptable,		2,	2,	},
	};
	int i;
	for (i=0; i<sizeof(f_tbl)/sizeof(*f_tbl); ++i) {
		SExp subr = gen_subr(f_tbl[i].cfunc, f_tbl[i].name, f_tbl[i].minargnum, f_tbl[i].maxargnum);
		SExp sym = intern(f_tbl[i].name);
		setq(sym, subr);
	}
}

